//
//  StaticMatrix.h
//  DiceWar
//
//  Created by xiaofeng on 19/6/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#ifndef CLASS_GAME_UTIL_STATICMATRIX_H_
#define CLASS_GAME_UTIL_STATICMATRIX_H_

#include "cocos2d.h"

template <typename ElementType, int SIZEX, int SIZEY>
class StaticMatrix
{
public:
    typedef const ElementType* const_iterator;
    typedef ElementType* iterator;
    
    StaticMatrix();
    ~StaticMatrix();
    
private:
    StaticMatrix(const StaticMatrix& other);
    StaticMatrix& operator=(const StaticMatrix& other);
    
public:
    /** set the value of the element at given location to the value of the element given
     */
    void setValue(int xIndex, int yIndex, ElementType value);
    void setAllValue(ElementType value);
    
    const ElementType& getValue(int xIndex, int yIndex) const;
    ElementType& getValue(int xIndex, int yIndex);
    
    const ElementType& operator()(int xIndex, int yIndex) const;
    ElementType& operator()(int xIndex, int yIndex);
    
    int getSizeX() const { return SIZEX; }
    int getSizeY() const { return SIZEY; }
    
    iterator begin() { return &m_data[0]; }
    const_iterator begin() const { return &m_data[0]; }
    
    iterator end() { return &m_data[SIZEX * SIZEY]; }
    const_iterator end() const { return &m_data[SIZEX * SIZEY]; }
    
private:
    int getOneDimensionIndex(int xIndex, int yIndex) const { return xIndex * SIZEY + yIndex; }
    
private:
    ElementType m_data[SIZEX * SIZEY + 1];
};

template <typename ElementType, int SIZEX, int SIZEY>
StaticMatrix<ElementType, SIZEX, SIZEY>::StaticMatrix() {}

template <typename ElementType, int SIZEX, int SIZEY>
StaticMatrix<ElementType, SIZEX, SIZEY>::~StaticMatrix() {}

template <typename ElementType, int SIZEX, int SIZEY>
void StaticMatrix<ElementType, SIZEX, SIZEY>::setValue(int xIndex, int yIndex, ElementType value)
{
    CCAssert(xIndex >= 0 && xIndex < SIZEX, "Invalid Coordinate X");
    CCAssert(yIndex >= 0 && yIndex < SIZEY, "Invalid Coordinate Y");
    m_data[getOneDimensionIndex(xIndex, yIndex)] = value;
}

template <typename ElementType, int SIZEX, int SIZEY>
ElementType& StaticMatrix<ElementType, SIZEX, SIZEY>::getValue(int xIndex, int yIndex)
{
    return const_cast<ElementType&>(const_cast<const StaticMatrix<ElementType, SIZEX, SIZEY>*>(this)->getValue(xIndex, yIndex));
}

template <typename ElementType, int SIZEX, int SIZEY>
const ElementType& StaticMatrix<ElementType, SIZEX, SIZEY>::getValue(int xIndex, int yIndex) const
{
    CCAssert(xIndex >= 0 && xIndex < SIZEX, "Invalid Coordinate X");
    CCAssert(yIndex >= 0 && yIndex < SIZEY, "Invalid Coordinate Y");
    return m_data[getOneDimensionIndex(xIndex, yIndex)];
}

template <typename ElementType, int SIZEX, int SIZEY>
void StaticMatrix<ElementType, SIZEX, SIZEY>::setAllValue(ElementType value)
{
    for (int index = 0; index < (SIZEX * SIZEY); index++)
        m_data[index] = value;
}

template <typename ElementType, int SIZEX, int SIZEY>
const ElementType& StaticMatrix<ElementType, SIZEX, SIZEY>::operator()(int xIndex, int yIndex) const
{
    CCAssert(xIndex >= 0 && xIndex < SIZEX, "Invalid Coordinate X");
    CCAssert(yIndex >= 0 && yIndex < SIZEY, "Invalid Coordinate Y");
    return m_data[getOneDimensionIndex(xIndex, yIndex)];
}

template <typename ElementType, int SIZEX, int SIZEY>
ElementType& StaticMatrix<ElementType, SIZEX, SIZEY>::operator()(int xIndex, int yIndex)
{
    return const_cast<ElementType&>(const_cast<const StaticMatrix<ElementType, SIZEX, SIZEY>*>(this)->operator()(xIndex, yIndex));
}

#endif //CLASS_GAME_UTIL_STATICMATRIX_H_
